package org.lilred.nzbberry.controllers;

import java.util.Vector;

import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.Menu;

import org.json.me.JSONArray;
import org.json.me.JSONObject;
import org.lilred.nzbberry.models.ConfigModel;
import org.lilred.nzbberry.models.QueueModel;
import org.lilred.nzbberry.models.QueueNzbModel;
import org.lilred.nzbberry.observer.Observable;
import org.lilred.nzbberry.observer.Observer;
import org.lilred.nzbberry.views.AppView;
import org.lilred.nzbberry.views.PageView;
import org.lilred.nzbberry.webservice.RequestsOutput;
import org.lilred.nzbberry.webservice.SabnzbdOutputClient;

public class QueueController extends PageController implements RequestsOutput, Observable {
	private QueueModel model;
	private Vector observers = new Vector();
	public static final int STARTED = 0;
	public static final int COMPLETED = 1;
	public static final int ERROR = 2;
	public static final int EMPTY = 3;

	public QueueController(QueueModel model) {
		this.view = new PageView() {
			protected void onVisibilityChange(boolean visible) {
				if (visible) refresh();
			}
		};
		this.model = model;
	}

	public void refresh() {
		SabnzbdOutputClient queueOutputClient = new SabnzbdOutputClient("queue", this);
		for(int i = 0; i < observers.size(); i++) {
			((Observer) observers.elementAt(i)).updateObserver(this, STARTED);
		}
		queueOutputClient.start();
	}

	public void webserviceOutputReceived(JSONObject output) {
		try {
			output = output.getJSONObject("queue");
			model.timeleft = output.getString("timeleft") + " left";
			model.kbps = output.getString("kbpersec") + " KB/s";
			model.paused = output.getBoolean("paused");
			model.uptime = output.getString("uptime");
			model.timeleft = output.getString("timeleft");

			//Account for each of the slots in the queue
			JSONArray slotsJsonArray;
			try {
				slotsJsonArray = output.getJSONArray("slots");
			} catch (Exception e) { slotsJsonArray = new JSONArray(); }
			AppView.getInstance().appManager.queueButton.setBadges(slotsJsonArray.length());
			for (int i = 0; i < slotsJsonArray.length(); i++) {
				//Instantiate a new NzbModel for each slot in the queue
				//Perhaps this is bad - too much object creation?
				QueueNzbModel m = new QueueNzbModel(slotsJsonArray.getJSONObject(i));

				//If the queue model's size is smaller than the size of the json array, we need
				//to create a new slot in our model
				if (model.size() <= i) {
					final QueueSlotController c = new QueueSlotController(this, m);
					model.addSlot(c);
					//Then we add it to the queue view
					UiApplication.getUiApplication().invokeLater(new Runnable() {
						public void run() {
							view.add(c.view);
						}
					});
				} else {
					//Otherwise, we just need to update the slot
					model.getSlot(i).setModel(m); 
				}
			}
			//Delete any extra slots that remain from downloads that completed or downloads that were deleted remotely
			for (int i = slotsJsonArray.length(); i < model.size(); i++) {
				final QueueSlotController c = model.getSlot(i);
				model.deleteSlot(c);
				UiApplication.getUiApplication().invokeLater(new Runnable() {
					public void run() {	
						try {
							view.delete(c.view);
						} catch (Exception e){
							System.out.println(e.getMessage());
						}
					}
				});
			}
			for (int i = 0; i < observers.size(); i++) {
				((Observer) observers.elementAt(i)).updateObserver(this, COMPLETED);
			}
		} catch (Exception e) {
			for (int i = 0; i < observers.size(); i++) {
				((Observer) observers.elementAt(i)).updateObserver(this, ERROR);
			}
		} 
	}

	public void webserviceRequestFailed() {
		for(int i = 0; i < observers.size(); i++) {
			((Observer) observers.elementAt(i)).updateObserver(this, ERROR);
		}
		try {
			Thread.sleep(ConfigModel.getConfig().getRefreshCurrentInterval());
		} catch (InterruptedException e) {
			System.out.println(e.getMessage());
		}
	}	

	public String getKbps() {
		return model.kbps;
	}

	public String getTimeLeft() {
		return model.timeleft;
	}

	public void registerObserver(Observer o) {
		observers.addElement(o);
	}

	public int size() {
		return model.size();
	}

	public void reorder() {
		//Look for any slots whose models are in the wrong place.
		//If there is a model in the wrong place, that means it was just moved but we haven't received
		//a status update from sabnzbd yet.
		for (int i = 0; i < model.size(); i++) {
			QueueNzbModel movedNzb = model.getSlot(i).model;
			if (movedNzb.getIndex() != i) {
				//We have found the NZB that wants to move.
				//He came from the slot (i) and wants to go to the index in his model.
				//displacedNzb is the nzb who needs to move to his former slot.
				QueueNzbModel displacedNzb = model.getSlot(movedNzb.getIndex()).model;
				model.getSlot(movedNzb.getIndex()).setModel(movedNzb);
				model.getSlot(i).setModel(displacedNzb);
				displacedNzb.setIndex(i);
				model.getSlot(movedNzb.getIndex()).view.setFocus();
				view.invalidate();
			}
		}
	}

	public void delete(QueueSlotController queueSlotController) {
		model.deleteSlot(queueSlotController);
		view.delete(queueSlotController.view);
	}

	public Menu makeMenu(Menu menu) {
		menu.add(refreshMenuItem);
		return menu;
	}
	

	MenuItem refreshMenuItem = new MenuItem("Refresh Queue", 60, 60) {
		public void run() {
			refresh();
		}
	};
}
